const SLIST_NULL: *mut std::ffi::c_void = std::ptr::null_mut();
type SListValue = *mut std::ffi::c_void;
#[repr(C)]
struct SListEntry {
    data: SListValue,
    next: *mut SListEntry,
}
#[repr(C)]
struct SListIterator {
    prev_next: *mut *mut SListEntry,
    current: *mut SListEntry,
}
type SListCompareFunc = fn(SListValue, SListValue) -> i32;
type SListEqualFunc = fn(SListValue, SListValue) -> i32;
fn slist_free(mut list: *mut SListEntry) {
    while !list.is_null() {
        unsafe {
            let next = (*list).next;
            libc::free(list as *mut libc::c_void);
            list = next;
        }
    }
}
fn slist_prepend(list: *mut *mut SListEntry, data: SListValue) -> *mut SListEntry {
    let newentry = unsafe { libc::malloc(std::mem::size_of::<SListEntry>()) as *mut SListEntry };
    if newentry.is_null() {
        return ptr::null_mut();
    }
    unsafe {
        (*newentry).data = data;
        (*newentry).next = *list;
        *list = newentry;
    }
    newentry
}
fn slist_append(list: &mut Option<Box<SListEntry>>, data: SListValue) -> Option<Box<SListEntry>> {
    let newentry = Box::new(SListEntry { data, next: None });
    if let None = *list {
        *list = Some(newentry);
    } else {
        let mut rover = list.as_mut().unwrap();
        while let Some(next) = rover.next.as_mut() {
            rover = next;
        }
        rover.next = Some(newentry);
    }
    list.as_ref().map(|entry| Box::new(entry.clone()))
}
fn slist_data(listentry: *mut SListEntry) -> SListValue {
    unsafe { (*listentry).data }
}
fn slist_set_data(listentry: *mut SListEntry, data: SListValue) {
    if !listentry.is_null() {
        unsafe {
            (*listentry).data = data;
        }
    }
}
fn slist_next(listentry: Option<Box<SListEntry>>) -> Option<Box<SListEntry>> {
    if let Some(entry) = listentry {
        entry.next
    } else {
        None
    }
}
fn slist_nth_entry(mut list: *mut SListEntry, n: u32) -> *mut SListEntry {
    for _ in 0..n {
        if list.is_null() {
            return std::ptr::null_mut();
        }
        unsafe {
            list = (*list).next;
        }
    }
    list
}
fn slist_nth_data(list: *mut SListEntry, n: u32) -> SListValue {
    let entry = unsafe { slist_nth_entry(list, n) };
    if entry.is_null() {
        SLIST_NULL
    } else {
        unsafe { (*entry).data }
    }
}
fn slist_length(list: *mut SListEntry) -> u32 {
    let mut entry = list;
    let mut length: u32 = 0;
    while !entry.is_null() {
        length += 1;
        unsafe {
            entry = (*entry).next;
        }
    }
    length
}
fn slist_to_array(list: *mut SListEntry) -> *mut SListValue {
    let length = unsafe { slist_length(list) } as usize;
    let array: *mut SListValue =
        unsafe { libc::malloc(std::mem::size_of::<SListValue>() * length) as *mut SListValue };
    if array.is_null() {
        return std::ptr::null_mut();
    }
    let mut rover = list;
    for i in 0..length {
        unsafe {
            *array.add(i) = (*rover).data;
            rover = (*rover).next;
        }
    }
    array
}
fn slist_remove_entry(list: *mut *mut SListEntry, entry: *mut SListEntry) -> i32 {
    if list.is_null() || entry.is_null() {
        return 0;
    }
    unsafe {
        if *list == entry {
            *list = (*entry).next;
        } else {
            let mut rover = *list;
            while !rover.is_null() && (*rover).next != entry {
                rover = (*rover).next;
            }
            if rover.is_null() {
                return 0;
            } else {
                (*rover).next = (*entry).next;
            }
        }
        free(entry as *mut _);
    }
    1
}
fn slist_remove_data(
    list: *mut *mut SListEntry,
    callback: SListEqualFunc,
    data: SListValue,
) -> u32 {
    let mut rover = list;
    let mut entries_removed = 0;
    unsafe {
        while !(*rover).is_null() {
            if callback((**rover).data, data) != 0 {
                let next = (**rover).next;
                libc::free(*rover as *mut _);
                *rover = next;
                entries_removed += 1;
            } else {
                rover = &mut (**rover).next;
            }
        }
    }
    entries_removed
}
fn slist_sort_internal(
    list: &mut *mut SListEntry,
    compare_func: SListCompareFunc,
) -> *mut SListEntry {
    let mut pivot: *mut SListEntry;
    let mut rover: *mut SListEntry;
    let mut less_list: *mut SListEntry = ptr::null_mut();
    let mut more_list: *mut SListEntry = ptr::null_mut();
    let mut less_list_end: *mut SListEntry;
    let mut more_list_end: *mut SListEntry;
    if (*list).is_null() || (**list).next.is_null() {
        return *list;
    }
    pivot = *list;
    rover = (**list).next;
    while !rover.is_null() {
        let next = (*rover).next;
        if compare_func((*rover).data, (*pivot).data) < 0 {
            (*rover).next = less_list;
            less_list = rover;
        } else {
            (*rover).next = more_list;
            more_list = rover;
        }
        rover = next;
    }
    less_list_end = slist_sort_internal(&mut less_list, compare_func);
    more_list_end = slist_sort_internal(&mut more_list, compare_func);
    *list = less_list;
    if less_list.is_null() {
        *list = pivot;
    } else {
        (*less_list_end).next = pivot;
    }
    (*pivot).next = more_list;
    if more_list.is_null() {
        return pivot;
    } else {
        return more_list_end;
    }
}
fn slist_sort(list: *mut *mut SListEntry, compare_func: SListCompareFunc) {
    slist_sort_internal(list, compare_func);
}
fn slist_find_data(
    list: *mut SListEntry,
    callback: SListEqualFunc,
    data: SListValue,
) -> *mut SListEntry {
    let mut rover = list;
    while !rover.is_null() {
        unsafe {
            if callback((*rover).data, data) != 0 {
                return rover;
            }
            rover = (*rover).next;
        }
    }
    std::ptr::null_mut()
}
fn slist_iterate(list: *mut *mut SListEntry, iter: *mut SListIterator) {
    unsafe {
        (*iter).prev_next = list;
        (*iter).current = std::ptr::null_mut();
    }
}
fn slist_iter_has_more(iter: *mut SListIterator) -> i32 {
    unsafe {
        if (*iter).current.is_null() || (*iter).current != *(*iter).prev_next {
            if !(*(*iter).prev_next).is_null() {
                1
            } else {
                0
            }
        } else {
            if !(*(*iter).current).next.is_null() {
                1
            } else {
                0
            }
        }
    }
}
fn slist_iter_next(iter: &mut SListIterator) -> SListValue {
    if iter.current.is_null() || iter.current != *iter.prev_next {
        iter.current = *iter.prev_next;
    } else {
        iter.prev_next = unsafe { &mut (*iter.current).next };
        iter.current = unsafe { (*iter.current).next };
    }
    if iter.current.is_null() {
        std::ptr::null_mut()
    } else {
        unsafe { (*iter.current).data }
    }
}
fn slist_iter_remove(iter: &mut SListIterator) {
    if iter.current.is_null() || iter.current != unsafe { *iter.prev_next } {
    } else {
        unsafe {
            *iter.prev_next = (*iter.current).next;
            libc::free(iter.current as *mut libc::c_void);
        }
        iter.current = std::ptr::null_mut();
    }
}
